/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package it.polimi.meteocal_pappalardo_sacchi.bean;
import it.polimi.meteocal_pappalardo_sacchi.entity.*;

import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.view.ViewScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;

/**
 *
 * Attenzione ad importare javax.faces.view.ViewScoped, l'altro non è compatibile con un CDI bean (i.e. @Named)
 */

@Named
@ViewScoped
public class EventBean implements Serializable {

    @Inject
    ScheduleBean scheduleBean;
    @Inject
    EventManager eventManager;
    @Inject
    UserManager userManager;
    @Inject
    UserBean userBean;
    @Inject
    WeatherManager weatherManager;
    @Inject
    NotificationManager notificationManager;
    @Inject
    ForecastBean forecastBean;
    
    private Event event;

    private List<MeteoCalUser> invitedUserListToNotify;
    private List<Calendar> invitedUserCalendarList;
    private List<MeteoCalUser> alreadyInvitedUserList;
    private String usernameToSearch;

    public EventBean(){
    }

    @PostConstruct
    private void eventInit(){
        setInvitedUserCalendarList(new ArrayList<Calendar>());
        setInvitedUserListToNotify(new ArrayList<MeteoCalUser>());
    }

    /* Methods to search and invite guests*/

    public void addInsertedUser() {
        if (usernameToSearch == null) {
            FacesMessage messageEmpty = new FacesMessage("Insert a username");
            FacesContext.getCurrentInstance().addMessage("eventForm:searchuser", messageEmpty);
            return;
        }
        MeteoCalUser userToAdd = userManager.find(usernameToSearch);
        if (checkUserToAdd(userToAdd)) {
            FacesMessage messageExist = new FacesMessage("User found");
            FacesContext.getCurrentInstance().addMessage("eventForm:searchuser", messageExist);
            addInvitedUserToNotifyList(userToAdd);
            addInvitedUserCalendarToInvitedList(userToAdd.getOwnedCalendar());
            //nullifico la stringa dopo che viene presa corettamente
            usernameToSearch = null;
            return;
        }
    }

    private boolean checkUserToAdd(MeteoCalUser userToAdd) {
        //se non trovo un utente con quell'username
        if (userToAdd == null) {
            FacesMessage messageNotExist = new FacesMessage("User doesn't exist");
            FacesContext.getCurrentInstance().addMessage("eventForm:searchuser", messageNotExist);
            return false;
            //se cerco di invitare me stesso
        } else if (userToAdd.equals(userBean.getUser())) {
            FacesMessage messageMyself = new FacesMessage("Inviting yourself doesn't make sense");
            FacesContext.getCurrentInstance().addMessage("eventForm:searchuser", messageMyself);
            return false;
            //se ho già aggiunto l'utente alla lista degli invitati
        } else if (invitedUserListToNotify != null && invitedUserListToNotify.contains(userToAdd)) {
            FacesMessage messageAlready = new FacesMessage("User already invited");
            FacesContext.getCurrentInstance().addMessage("eventForm:searchuser", messageAlready);
            return false;
            //se sto eseguendo la modifica di un evento e cerco di aggiungere un utente già invitato
        } else if (alreadyInvitedUserList != null && alreadyInvitedUserList.contains(userToAdd)){
            FacesMessage messageAlready = new FacesMessage("User previously invited");
            FacesContext.getCurrentInstance().addMessage("eventForm:searchuser", messageAlready);
            return false;
        }
        return true;
    }

    /*Field checkers*/

    protected boolean checkAll() {
        if (checkRequiredFieldsSet()) {
            return false;
        }
        if (checkDateOrder()) {
            return false;
        }
        if(checkTimeOrder()) {
            return false;
        }
        if(checkEventInThePast()) {
            return false;
        }
        return true;
    }

    private boolean checkRequiredFieldsSet() {
        boolean areFieldsInvalid = false;
        if (getEvent().getTitle() == null) {
            FacesMessage messageTitle = new FacesMessage("Insert a title");
            FacesContext.getCurrentInstance().addMessage("eventForm:title", messageTitle);
            areFieldsInvalid = true;
        }

        if (getEvent().getDescription() == null) {
            FacesMessage messageDescription = new FacesMessage("Insert a description");
            FacesContext.getCurrentInstance().addMessage("eventForm:description", messageDescription);
            areFieldsInvalid = true;
        }

        if (getEvent().getAddressWithoutCity() == null) {
            FacesMessage messageAddress = new FacesMessage("Insert an address");
            FacesContext.getCurrentInstance().addMessage("eventForm:address", messageAddress);
            areFieldsInvalid = true;
        }
        
        if (getEvent().getCity() == null) {
            FacesMessage messageCity = new FacesMessage("Insert a city");
            FacesContext.getCurrentInstance().addMessage("eventForm:city", messageCity);
            areFieldsInvalid = true;
        }

        if (getEvent().getStartingTime() == null) {
            FacesMessage messageStartingTime = new FacesMessage("Insert a starting time");
            FacesContext.getCurrentInstance().addMessage("eventForm:startingtime", messageStartingTime);
            areFieldsInvalid = true;
        }

        if (getEvent().getEndingTime() == null) {
            FacesMessage messageEndingTime = new FacesMessage("Insert an ending time");
            FacesContext.getCurrentInstance().addMessage("eventForm:endingtime", messageEndingTime);
            areFieldsInvalid = true;
        }

        if (getEvent().getStartingDate() == null) {
            FacesMessage messageStartingDate = new FacesMessage("Insert a starting date");
            FacesContext.getCurrentInstance().addMessage("eventForm:startingdate", messageStartingDate);
            areFieldsInvalid = true;
        }

        if (getEvent().getEndingDate() == null) {
            FacesMessage messageEndingDate = new FacesMessage("Insert an ending date");
            FacesContext.getCurrentInstance().addMessage("eventForm:endingdate", messageEndingDate);
            areFieldsInvalid = true;
        }
        return areFieldsInvalid;
    }

    private boolean checkDateOrder() {
        if (getEvent().getStartingDate().after(getEvent().getEndingDate())) {
            FacesMessage message = new FacesMessage("The starting date can't be after the ending date");
            FacesContext.getCurrentInstance().addMessage("eventForm:startingdate", message);
            return true;
        }
        return false;
    }

    private boolean checkTimeOrder() {
        if (getEvent().getStartingDate().equals(getEvent().getEndingDate()) && getEvent().getStartingTime().after(getEvent().getEndingTime())) {
            FacesMessage message = new FacesMessage("The starting time can't be after the ending time on the same day");
            FacesContext.getCurrentInstance().addMessage("eventForm:startingtime", message);
            return true;
        }
        return false;
    }

    private boolean checkEventInThePast() {
        ZoneId zone = ZoneId.of("Europe/Paris");
        LocalDate today = LocalDate.now(zone);
        LocalTime now = LocalTime.now(zone);
        if (getEvent().getStartingDate().toLocalDate().isBefore(today)) {
            FacesMessage message = new FacesMessage("The starting date can't be before today");
            FacesContext.getCurrentInstance().addMessage("eventForm:startingdate", message);
            return true;
        } else if (getEvent().getStartingDate().toLocalDate().isEqual(today) && getEvent().getStartingTime().toLocalTime().isBefore(now)) {
            FacesMessage message = new FacesMessage("The starting time can't be before now");
            FacesContext.getCurrentInstance().addMessage("eventForm:startingtime", message);
            return true;
        }
        return false;
    }

    protected void addInvitedUserCalendarToInvitedList(Calendar calendar) {
        invitedUserCalendarList.add(calendar);
    }

    protected void addInvitedUserToNotifyList(MeteoCalUser user) {
        invitedUserListToNotify.add(user);
    }

    public List<MeteoCalUser> getInvitedUserListToNotify() {
        return invitedUserListToNotify;
    }

    public void setInvitedUserListToNotify(List<MeteoCalUser> invitedUserListToNotify) {
        this.invitedUserListToNotify = invitedUserListToNotify;
    }

    public String getUsernameToSearch() {
        return usernameToSearch;
    }

    public void setUsernameToSearch(String usernameToSearch) {
        this.usernameToSearch = usernameToSearch;
    }

    public List<MeteoCalUser> getAlreadyInvitedUserList() {
        return alreadyInvitedUserList;
    }

    public void setAlreadyInvitedUserList(List<MeteoCalUser> alreadyInvitedUserList) {
        this.alreadyInvitedUserList = alreadyInvitedUserList;
    }

    public Event getEvent() {
        return event;
    }

    public void setEvent(Event event) {
        this.event = event;
    }

    public List<Calendar> getInvitedUserCalendarList() {
        return invitedUserCalendarList;
    }

    public void setInvitedUserCalendarList(List<Calendar> invitedUserCalendarList) {
        this.invitedUserCalendarList = invitedUserCalendarList;
    }

    /* setters and getters for time and date*/
    public java.util.Date getStartingTime() {
        return (java.util.Date) this.getEvent().getStartingTime();
    }

    public void setStartingTime(java.util.Date date) {
        //questo controllo serve per far comparire correttamente il messaggio di errore inserisci time
        if (date == null) {
            return;
        }
        this.getEvent().setStartingTime(new java.sql.Time(date.getTime()));
    }

    public java.util.Date getEndingTime() {
        return (java.util.Date) this.getEvent().getEndingTime();
    }

    public void setEndingTime(java.util.Date date) {
        //questo controllo serve per far comparire correttamente il messaggio di errore inserisci time
        if (date == null) {
            return;
        }
        this.getEvent().setEndingTime(new java.sql.Time(date.getTime()));
    }

    public java.util.Date getStartingDate() {
        return (java.util.Date) this.getEvent().getStartingDate();
    }

    public void setStartingDate(java.util.Date date) {
        //questo controllo serve per far comparire correttamente il messaggio di errore inserisci date
        if (date == null) {
            return;
        }
        this.getEvent().setStartingDate(new java.sql.Date(date.getTime()));
    }

    public java.util.Date getEndingDate() {
        return (java.util.Date) this.getEvent().getEndingDate();
    }

    public void setEndingDate(java.util.Date date) {
        //questo controllo serve per far comparire correttamente il messaggio di errore inserisci date
        if (date == null) {
            return;
        }
        this.getEvent().setEndingDate(new java.sql.Date(date.getTime()));
    }
}
